/**
 ***********************************************************************************************************************
 * Copyright (c) 2020, China Mobile Communications Group Co.,Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * @file        tts_player_wav.c
 *
 * @brief       tts wav format API
 *
 * @revision
 * Date         Author          Notes
 * 2020-11-20   OneOS Team      First Version
 ***********************************************************************************************************************
 */

#include <os_task.h>
#include <os_device.h>
#include <vfs_posix.h>
#include <audio/audio.h>
#include <shell.h>

#define BUFSZ   OS_AUDIO_REPLAY_MP_BLOCK_SIZE                                           
#define SOUND_DEVICE_NAME    "audio0"    /* Audio device name */

struct RIFF_HEADER_DEF
{
    char riff_id[4];     /* 'R','I','F','F' */
    uint32_t riff_size;
    char riff_format[4]; /* 'W','A','V','E' */
};

struct WAVE_FORMAT_DEF
{
    uint16_t FormatTag;
    uint16_t Channels;
    uint32_t SamplesPerSec;
    uint32_t AvgBytesPerSec;
    uint16_t BlockAlign;
    uint16_t BitsPerSample;
};

struct FMT_BLOCK_DEF
{
    char fmt_id[4];    /* 'f','m','t',' ' */
    uint32_t fmt_size;
    struct WAVE_FORMAT_DEF wav_format;
};

struct DATA_BLOCK_DEF
{
    char data_id[4];     /* 'R','I','F','F' */
    uint32_t data_size;
};

struct wav_info
{
    struct RIFF_HEADER_DEF header;
    struct FMT_BLOCK_DEF   fmt_block;
    struct DATA_BLOCK_DEF  data_block;
};

int wav_player(char *wav_file)
{
    int fd = -1;
    uint8_t *buffer = NULL;
    struct wav_info *info = NULL;
    struct os_audio_caps caps = {0};
    os_device_t *snd_dev;


    os_task_t *self = os_task_self();
    os_uint8_t task_prio = self->current_priority;
    os_uint8_t high_prio = 1;
    os_task_control(self, OS_TASK_CTRL_CHANGE_PRIORITY, &high_prio);

    fd = open(wav_file, O_RDONLY);
    if (fd < 0)
    {
        os_kprintf("open file failed!\n");
        goto __exit;
    }

    buffer = os_malloc(BUFSZ);
    if (buffer == OS_NULL)
        goto __exit;

    info = (struct wav_info *) os_malloc(sizeof * info);
    if (info == OS_NULL)
        goto __exit;

    if (read(fd, &(info->header), sizeof(struct RIFF_HEADER_DEF)) <= 0)    
        goto __exit;
    if (read(fd, &(info->fmt_block),  sizeof(struct FMT_BLOCK_DEF)) <= 0)
        goto __exit;
    if (read(fd, &(info->data_block), sizeof(struct DATA_BLOCK_DEF)) <= 0)
        goto __exit;

    os_kprintf("wav information:\n");
    os_kprintf("samplerate %d\n", info->fmt_block.wav_format.SamplesPerSec);
    os_kprintf("channel %d\n", info->fmt_block.wav_format.Channels);

    snd_dev = os_device_find(SOUND_DEVICE_NAME);
    OS_ASSERT(snd_dev != OS_NULL);

    os_device_open(snd_dev, OS_DEVICE_OFLAG_WRONLY);

    /* parameter settings */                         
    caps.config_type = AUDIO_PARAM_CMD;    
    caps.udata.config.samplerate = info->fmt_block.wav_format.SamplesPerSec;    
    caps.udata.config.channels   = info->fmt_block.wav_format.Channels;                                                  
    os_device_control(snd_dev, AUDIO_CTL_CONFIGURE, &caps);      
    caps.config_type = AUDIO_VOLUME_CMD;
    caps.udata.value = 35;
    os_device_control(snd_dev, AUDIO_CTL_CONFIGURE, &caps);                                    

    while (1)
    {
        int length;
      
        length = read(fd, buffer, BUFSZ);  
        if (length <= 0)
            break;
        
        os_device_write(snd_dev, 0, buffer, length);
    }

    os_device_close(snd_dev);

__exit:

    if (fd >= 0)
        close(fd);

    if (buffer)
        os_free(buffer);

    if (info)
        os_free(info);

    os_task_control(self, OS_TASK_CTRL_CHANGE_PRIORITY, &task_prio);

    return 0;
}


